#include <asm/shadow.h>
#include <asm/tboot.h>
+static int opt_vpid_enabled = 1;
+boolean_param("vpid", opt_vpid_enabled);
+
/* Dynamic (run-time adjusted) execution control flags. */
u32 vmx_pin_based_exec_control __read_mostly;
u32 vmx_cpu_based_exec_control __read_mostly;
opt = (SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES |
SECONDARY_EXEC_WBINVD_EXITING |
SECONDARY_EXEC_ENABLE_EPT);
+ if ( opt_vpid_enabled )
+ opt |= SECONDARY_EXEC_ENABLE_VPID;
_vmx_secondary_exec_control = adjust_vmx_controls(
min, opt, MSR_IA32_VMX_PROCBASED_CTLS2);
}
ept_sync_all();
+ vpid_sync_all();
+
return 1;
}
#endif
}
+ if ( cpu_has_vmx_vpid )
+ {
+ v->arch.hvm_vmx.vpid =
+ v->domain->arch.hvm_domain.vmx.vpid_base + v->vcpu_id;
+ __vmwrite(VIRTUAL_PROCESSOR_ID, v->arch.hvm_vmx.vpid);
+ }
+
vmx_vmcs_exit(v);
paging_update_paging_modes(v); /* will update HOST & GUEST_CR3 as reqd */
vmx_load_vmcs(v);
hvm_migrate_timers(v);
vmx_set_host_env(v);
+ vpid_sync_vcpu_all(v);
}
debug_state = v->domain->debugger_attached;
(uint32_t)vmr(TPR_THRESHOLD));
printk("EPT pointer = 0x%08x%08x\n",
(uint32_t)vmr(EPT_POINTER_HIGH), (uint32_t)vmr(EPT_POINTER));
+ printk("Virtual processor ID = 0x%04x\n",
+ (uint32_t)vmr(VIRTUAL_PROCESSOR_ID));
vmx_vmcs_exit(v);
}
static int vmx_alloc_vlapic_mapping(struct domain *d);
static void vmx_free_vlapic_mapping(struct domain *d);
+static int vmx_alloc_vpid(struct domain *d);
+static void vmx_free_vpid(struct domain *d);
static void vmx_install_vlapic_mapping(struct vcpu *v);
static void vmx_update_guest_cr(struct vcpu *v, unsigned int cr);
static void vmx_update_guest_efer(struct vcpu *v);
static int vmx_domain_initialise(struct domain *d)
{
+ int rc;
+
d->arch.hvm_domain.vmx.ept_control.etmt = EPT_DEFAULT_MT;
d->arch.hvm_domain.vmx.ept_control.gaw = EPT_DEFAULT_GAW;
d->arch.hvm_domain.vmx.ept_control.asr =
pagetable_get_pfn(d->arch.phys_table);
- return vmx_alloc_vlapic_mapping(d);
+ if ( (rc = vmx_alloc_vpid(d)) != 0 )
+ return rc;
+
+ if ( (rc = vmx_alloc_vlapic_mapping(d)) != 0 )
+ {
+ vmx_free_vpid(d);
+ return rc;
+ }
+
+ return 0;
}
static void vmx_domain_destroy(struct domain *d)
{
ept_sync_domain(d);
vmx_free_vlapic_mapping(d);
+ vmx_free_vpid(d);
}
static int vmx_vcpu_initialise(struct vcpu *v)
}
__vmwrite(GUEST_CR3, v->arch.hvm_vcpu.hw_cr[3]);
+ vpid_sync_vcpu_all(v);
break;
case 4:
v->arch.hvm_vcpu.hw_cr[4] = HVM_CR4_HOST_MASK;
static void vmx_flush_guest_tlbs(void)
{
- /* No tagged TLB support on VMX yet. The fact that we're in Xen
- * at all means any guest will have a clean TLB when it's next run,
- * because VMRESUME will flush it for us. */
+ /*
+ * If VPID (i.e. tagged TLB support) is not enabled, the fact that
+ * we're in Xen at all means any guest will have a clean TLB when
+ * it's next run, because VMRESUME will flush it for us.
+ *
+ * If enabled, we invalidate all translations associated with all
+ * VPID values.
+ */
+ vpid_sync_all();
}
static void __ept_sync_domain(void *info)
.invlpg_intercept = vmx_invlpg_intercept
};
+static unsigned long *vpid_bitmap;
+#define VPID_BITMAP_SIZE ((1u << VMCS_VPID_WIDTH) / MAX_VIRT_CPUS)
+
void start_vmx(void)
{
static int bootstrapped;
vmx_function_table.hap_supported = 1;
}
+ if ( cpu_has_vmx_vpid )
+ {
+ printk("VMX: VPID is available.\n");
+
+ vpid_bitmap = xmalloc_array(
+ unsigned long, BITS_TO_LONGS(VPID_BITMAP_SIZE));
+ BUG_ON(vpid_bitmap == NULL);
+ memset(vpid_bitmap, 0, BITS_TO_LONGS(VPID_BITMAP_SIZE) * sizeof(long));
+
+ /* VPID 0 is used by VMX root mode (the hypervisor). */
+ __set_bit(0, vpid_bitmap);
+ }
+
setup_vmcs_dump();
hvm_enable(&vmx_function_table);
free_xenheap_page(mfn_to_virt(mfn));
}
+static int vmx_alloc_vpid(struct domain *d)
+{
+ int idx;
+
+ if ( !cpu_has_vmx_vpid )
+ return 0;
+
+ do {
+ idx = find_first_zero_bit(vpid_bitmap, VPID_BITMAP_SIZE);
+ if ( idx >= VPID_BITMAP_SIZE )
+ {
+ dprintk(XENLOG_WARNING, "VMX VPID space exhausted.\n");
+ return -EBUSY;
+ }
+ }
+ while ( test_and_set_bit(idx, vpid_bitmap) );
+
+ d->arch.hvm_domain.vmx.vpid_base = idx * MAX_VIRT_CPUS;
+ return 0;
+}
+
+static void vmx_free_vpid(struct domain *d)
+{
+ if ( !cpu_has_vmx_vpid )
+ return;
+
+ clear_bit(d->arch.hvm_domain.vmx.vpid_base / MAX_VIRT_CPUS, vpid_bitmap);
+}
+
static void vmx_install_vlapic_mapping(struct vcpu *v)
{
paddr_t virt_page_ma, apic_page_ma;
struct vmx_domain {
unsigned long apic_access_mfn;
-
+ unsigned long vpid_base;
union {
struct {
u64 etmt :3,
u32 exec_control;
u32 secondary_exec_control;
+ u16 vpid;
+
/* PMU */
struct vpmu_struct vpmu;
#define SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES 0x00000001
#define SECONDARY_EXEC_ENABLE_EPT 0x00000002
+#define SECONDARY_EXEC_ENABLE_VPID 0x00000020
#define SECONDARY_EXEC_WBINVD_EXITING 0x00000040
extern u32 vmx_secondary_exec_control;
(vmx_cpu_based_exec_control & CPU_BASED_ACTIVATE_SECONDARY_CONTROLS)
#define cpu_has_vmx_ept \
(vmx_secondary_exec_control & SECONDARY_EXEC_ENABLE_EPT)
+#define cpu_has_vmx_vpid \
+ (vmx_secondary_exec_control & SECONDARY_EXEC_ENABLE_VPID)
/* GUEST_INTERRUPTIBILITY_INFO flags. */
#define VMX_INTR_SHADOW_STI 0x00000001
/* VMCS field encodings. */
enum vmcs_field {
+ VIRTUAL_PROCESSOR_ID = 0x00000000,
GUEST_ES_SELECTOR = 0x00000800,
GUEST_CS_SELECTOR = 0x00000802,
GUEST_SS_SELECTOR = 0x00000804,
HOST_RIP = 0x00006c16,
};
+#define VMCS_VPID_WIDTH 16
+
void vmx_disable_intercept_for_msr(struct vcpu *v, u32 msr);
int vmx_read_guest_msr(struct vcpu *v, u32 msr, u64 *val);
int vmx_write_guest_msr(struct vcpu *v, u32 msr, u64 val);
#define VMRESUME_OPCODE ".byte 0x0f,0x01,0xc3\n"
#define VMWRITE_OPCODE ".byte 0x0f,0x79\n"
#define INVEPT_OPCODE ".byte 0x66,0x0f,0x38,0x80\n" /* m128,r64/32 */
+#define INVVPID_OPCODE ".byte 0x66,0x0f,0x38,0x81\n" /* m128,r64/32 */
#define VMXOFF_OPCODE ".byte 0x0f,0x01,0xc4\n"
#define VMXON_OPCODE ".byte 0xf3,0x0f,0xc7\n"
u64 eptp, gpa;
} operand = {eptp, gpa};
- __asm__ __volatile__ ( INVEPT_OPCODE
- MODRM_EAX_08
- /* CF==1 or ZF==1 --> rc = -1 */
- "ja 1f ; ud2 ; 1:\n"
- :
- : "a" (&operand), "c" (ext)
- : "memory");
+ asm volatile ( INVEPT_OPCODE
+ MODRM_EAX_08
+ /* CF==1 or ZF==1 --> rc = -1 */
+ "ja 1f ; ud2 ; 1:\n"
+ :
+ : "a" (&operand), "c" (ext)
+ : "memory" );
+}
+
+static inline void __invvpid(int ext, u16 vpid, u64 gva)
+{
+ struct {
+ u64 vpid:16;
+ u64 rsvd:48;
+ u64 gva;
+ } __attribute__ ((packed)) operand = {vpid, 0, gva};
+
+ asm volatile ( INVVPID_OPCODE
+ MODRM_EAX_08
+ /* CF==1 or ZF==1 --> rc = -1 */
+ "ja 1f ; ud2 ; 1:\n"
+ :
+ : "a" (&operand), "c" (ext)
+ : "memory" );
}
static inline void ept_sync_all(void)
void ept_sync_domain(struct domain *d);
+static inline void vpid_sync_vcpu_all(struct vcpu *v)
+{
+ if ( cpu_has_vmx_vpid )
+ __invvpid(1, v->arch.hvm_vmx.vpid, 0);
+}
+
+static inline void vpid_sync_all(void)
+{
+ if ( cpu_has_vmx_vpid )
+ __invvpid(2, 0, 0);
+}
+
static inline void __vmxoff(void)
{
asm volatile (